package com.wflow.workflow.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wflow.bean.do_.UserDo;
import com.wflow.bean.entity.WflowCcTasks;
import com.wflow.bean.entity.WflowModelHistorys;
import com.wflow.bean.entity.WflowModels;
import com.wflow.exception.BusinessException;
import com.wflow.mapper.*;
import com.wflow.service.OrgRepositoryService;
import com.wflow.utils.UserUtil;
import com.wflow.workflow.bean.dto.ProcessInstanceOwnerDto;
import com.wflow.workflow.bean.process.OperationPerm;
import com.wflow.workflow.bean.process.OrgUser;
import com.wflow.workflow.bean.process.ProcessNode;
import com.wflow.workflow.bean.process.enums.ApprovalModeEnum;
import com.wflow.workflow.bean.process.enums.NodeTypeEnum;
import com.wflow.workflow.bean.process.enums.ProcessResultEnum;
import com.wflow.workflow.bean.process.form.Form;
import com.wflow.workflow.bean.process.props.ApprovalProps;
import com.wflow.workflow.bean.process.props.RootProps;
import com.wflow.workflow.bean.vo.*;
import com.wflow.workflow.config.WflowGlobalVarDef;
import com.wflow.workflow.service.*;
import com.wflow.workflow.utils.Executor;
import lombok.extern.slf4j.Slf4j;

import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : willian fu
 * @date : 2022/8/23
 */
@Slf4j
@Service
public class ProcessInstanceServiceImpl implements ProcessInstanceService {

    @Autowired
    private OrgRepositoryService orgRepositoryService;

    @Autowired
    private WflowModelsMapper modelsMapper;

    @Autowired
    private WflowModelHistorysMapper modelHistorysMapper;

    @Autowired
    private ProcessNodeCatchService nodeCatchService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private UserDeptOrLeaderService userDeptOrLeaderService;

    @Autowired
    private ProcessTaskService processTaskService;

    @Autowired
    private WflowCcTasksMapper ccTasksMapper;

    @Autowired
    private FormService formService;


    @Override
    @Transactional
    public String startProcess(String defId, ProcessStartParamsVo params) {
        Map<String, Object> processVar = new HashMap<>();
        processVar.putAll(params.getFormData());
        processVar.putAll(params.getProcessUsers());
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(defId).latestVersion().singleResult();
        if (ObjectUtil.isNotNull(processDefinition) && processDefinition.isSuspended()) {
            throw new BusinessException("流程未启用，请先启用");
        }
        //设置发起的人员及部门信息
        String userId = UserUtil.getLoginUserId();
        String userName = orgRepositoryService.getUserById(userId).getUserName();
        String deptName = orgRepositoryService.getDeptById(params.getDeptId()).getDeptName();
        processVar.put("owner", ProcessInstanceOwnerDto.builder()
                .owner(userId)
                .ownerName(userName)
                .ownerDeptId(params.getDeptId())
                .ownerDeptName(deptName)
                .build());
        WflowModels wflowModels = modelsMapper.selectOne(new LambdaQueryWrapper<WflowModels>().eq(WflowModels::getProcessDefId, defId));
        Map<String, ProcessNode<?>> nodeMap = nodeCatchService.reloadProcessByStr(wflowModels.getProcess());
        Map<String, Object> propsMap = nodeMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
                v -> null == v.getValue().getProps() ? new HashMap<>() : v.getValue().getProps()));
        //将表单及流程配置设置为变量，跟随版本
        processVar.put(WflowGlobalVarDef.WFLOW_NODE_PROPS, propsMap);
        processVar.put(WflowGlobalVarDef.WFLOW_FORMS, JSONArray.parseArray(wflowModels.getFormItems(), Form.class));
        //processVar.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", false);
        //processVar.put("approve", true);
        processVar.put(WflowGlobalVarDef.INITIATOR, userId);
        //这样做貌似无效果，变量表不会多INITIATOR变量，但是流程表发起人有效
        Authentication.setAuthenticatedUserId(userId);
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(defId, processVar);
        log.info("启动 {} 流程实例 {} 成功", processInstance.getProcessDefinitionName(), processInstance.getProcessInstanceId());
        //自动完成发起人节点任务
        Task rootTask = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).active().singleResult();
        if (Objects.nonNull(rootTask)) {
            taskService.complete(rootTask.getId());
        }
        Authentication.setAuthenticatedUserId(null);
        return processInstance.getProcessInstanceId();
    }

    @Override
    public String getBeforeTask(String instanceId, String task) {
        return null;
    }

    @Override
    @Transactional
    public void delProcessInstance(String instanceId) {
        // 删除流程实例
        try {
            runtimeService.deleteProcessInstance(instanceId, "删除");
        } catch (Exception ignored) {}
        // 删除流程历史实例
        historyService.deleteHistoricProcessInstance(instanceId);
        //删除的同时相关抄送表数据也要删除，不然分页数据会错
        ccTasksMapper.delete(new LambdaQueryWrapper<WflowCcTasks>().eq(WflowCcTasks::getInstanceId, instanceId));
        log.info("删除流程实例[{}]成功", instanceId);
    }

    @Override
    public ProcessProgressVo getInstanceProgress(String nodeId, String instanceId) {
        HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        //优化查询，把之前查好几次的一次性查出来然后再分类
        List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery()
                .processInstanceId(instanceId).executionId(instanceId).list();
        //数据分类 表单配置及数据、审批任务结果、
        ProcessInstanceOwnerDto owner = null;
        List<Form> forms = Collections.emptyList();
        Map<String, Object> formDatas = new HashMap<>();
        Map<String, ProcessHandlerParamsVo.Action> approvalResults = new HashMap<>();
        Map<String, Object> nodeProps = new HashMap<>();
        Map<String, String> signs = new HashMap<>();
        //遍历所有变量，将数据分类
        for (HistoricVariableInstance var : variables) {
            if (var.getVariableName().startsWith("approve_")) {
                approvalResults.put(var.getVariableName(), (ProcessHandlerParamsVo.Action) var.getValue());
            } else if (var.getVariableName().startsWith("field")) {
                formDatas.put(var.getVariableName(), var.getValue());
            } else if (var.getVariableName().startsWith("sign_")) {
                signs.put(var.getVariableName().substring(5), String.valueOf(var.getValue()));
            } else if (WflowGlobalVarDef.WFLOW_FORMS.equals(var.getVariableName())) {
                forms = (List<Form>) var.getValue();
            } else if (WflowGlobalVarDef.WFLOW_NODE_PROPS.equals(var.getVariableName())) {
                nodeProps = (Map<String, Object>)var.getValue();
            } else if ("owner".equals(var.getVariableName())) {
                owner = (ProcessInstanceOwnerDto) var.getValue();
            }
        }
        ProcessNode<?> currentNode = null;
        String modelFormConfig = null;
        ProcessProgressVo.InstanceExternSetting externSetting = null;
        if (StrUtil.isNotBlank(nodeId)) {
            //搜索当前版本流程的配置
            WflowModelHistorys modelHistory = modelHistorysMapper.selectOne(new LambdaQueryWrapper<>(WflowModelHistorys.builder()
                    .processDefId(instance.getProcessDefinitionId()).version(instance.getProcessDefinitionVersion()).build()));
            currentNode = nodeCatchService.reloadProcessByStr(modelHistory.getProcess()).get(nodeId);
            modelFormConfig = modelHistory.getFormConfig();
            externSetting = getExternSetting(modelHistory.getSettings(), instance.getStartUserId());
        }
        UserDo users = orgRepositoryService.getUserById(instance.getStartUserId());
        OrgUser startUser = OrgUser.builder().id(users.getUserId()).name(users.getUserName()).avatar(users.getAvatar()).build();
        List<ProcessProgressVo.ProgressNode> taskRecords = getHisTaskRecords(instanceId, nodeProps, approvalResults, signs);
        taskRecords.addAll(getCcTaskRecords(instanceId));
        if (ObjectUtil.isNull(instance.getEndTime())) {
            taskRecords.addAll(processTaskService.getFutureTask(instanceId));
        }
        taskRecords = taskRecords.stream()
                .sorted(Comparator.comparing(ProcessProgressVo.ProgressNode::getStartTime))
                .collect(Collectors.toList());
        ProcessProgressVo.ProgressNode progressNode = taskRecords.stream()
                .filter(n -> "root".equals(n.getNodeId()) && Objects.isNull(n.getResult()))
                .findFirst().orElse(null);
        if (Objects.nonNull(progressNode)) {
            //辅助前端UI构建，第一条一般都是
            progressNode.setResult(ProcessHandlerParamsVo.Action.agree);
            progressNode.setNodeType(NodeTypeEnum.ROOT);
        } else {
            //没有就进行构建，兼容之前的流程
            taskRecords.add(0, ProcessProgressVo.ProgressNode.builder()
                    .nodeId("root")
                    .name("提交申请")
                    .user(startUser)
                    .nodeType(NodeTypeEnum.ROOT)
                    .startTime(instance.getStartTime())
                    .finishTime(instance.getStartTime())
                    .taskId("root")
                    .result(ProcessHandlerParamsVo.Action.agree)
                    .build());
        }
        //提取全量表单数据
        if (StrUtil.isBlank(modelFormConfig)) {
            WflowModelHistorys modelHistory = modelHistorysMapper.selectOne(new LambdaQueryWrapper<>(WflowModelHistorys.builder()
                    .processDefId(instance.getProcessDefinitionId()).version(instance.getProcessDefinitionVersion()).build()));
            modelFormConfig = modelHistory.getFormConfig();
            externSetting = getExternSetting(modelHistory.getSettings(), instance.getStartUserId());
        }
        ProcessResultEnum processResult = ProcessResultEnum.resolveResult(instance.getEndActivityId());
        return ProcessProgressVo.builder()
                .instanceId(instanceId)
                .version(instance.getProcessDefinitionVersion())
                .formItems(formService.filterFormAndDataByPermConfig(forms, formDatas, currentNode))
                .formConfig(JSONObject.parseObject(modelFormConfig))
                .formData(formDatas)
                .processDefName(instance.getProcessDefinitionName())
                .staterUser(startUser)
                .starterDept(null == owner ? null : owner.getOwnerDeptName())
                .status(processResult.getDesc())
                .result(processResult)
                .startTime(instance.getStartTime())
                .finishTime(instance.getEndTime())
                .progress(taskRecords)
                .operationPerm(getOperationPerm(currentNode))
                .externSetting(externSetting)
                .build();
    }

    /**
     * 获取流程的审批历史记录
     *
     * @param instanceId 审批实例ID
     * @param nodeProps  节点设置
     * @return 历史记录列表
     */
    private List<ProcessProgressVo.ProgressNode> getHisTaskRecords(String instanceId, Map<String, Object> nodeProps,
                                                                   Map<String, ProcessHandlerParamsVo.Action> varMap,
                                                                   Map<String, String> signs) {
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId).orderByHistoricActivityInstanceStartTime().asc().list();
        Set<String> userSet = new HashSet<>();
        //获取节点处理结果
        Map<String, List<TaskCommentVo>> commentMap = new HashMap<>();
        //统一处理所有评论数据，省的多次查询
        List<TaskCommentVo> cmvos = taskService.getProcessInstanceComments(instanceId).stream().map(comment -> {
            userSet.add(comment.getUserId());
            TaskCommentVo commentVo = TaskCommentVo.builder()
                    .id(comment.getId())
                    .taskId(comment.getTaskId())
                    .commentType(comment.getType())
                    .type("COMMENT")
                    .createTime(comment.getTime())
                    .user(OrgUser.builder().id(comment.getUserId()).build())
                    .build();
            ProcessHandlerParamsVo.ProcessComment processComment = JSONObject.parseObject(comment.getFullMessage(), ProcessHandlerParamsVo.ProcessComment.class);
            commentVo.setText(processComment.getText());
            commentVo.setAttachments(processComment.getAttachments());
            return commentVo;
        }).collect(Collectors.toList());
        cmvos.forEach(cm -> {
            //把评论数据按照task进行归类
            String taskId = Optional.ofNullable(cm.getTaskId()).orElse(instanceId);
            List<TaskCommentVo> vos = commentMap.computeIfAbsent(taskId, k -> new ArrayList<>());
            vos.add(cm);
        });
        List<ProcessProgressVo.ProgressNode> progressNodes = list.stream().filter(his -> ObjectUtil.isNotNull(his.getTaskId())).map(his -> {
            Object props = nodeProps.get(his.getActivityId());
            ApprovalModeEnum approvalMode = null;
            if (props instanceof ApprovalProps) {
                approvalMode = ((ApprovalProps) props).getMode();
            }
            userSet.add(his.getAssignee());
            List<TaskCommentVo> commentVos = commentMap.getOrDefault(his.getTaskId(), Collections.emptyList());
            return ProcessProgressVo.ProgressNode.builder()
                    .nodeId(his.getActivityId())
                    .name(his.getActivityName())
                    .nodeType(NodeTypeEnum.APPROVAL)
                    .user(OrgUser.builder().id(his.getAssignee()).build())
                    .startTime(his.getStartTime())
                    .finishTime(his.getEndTime())
                    .taskId(his.getTaskId())
                    .approvalMode(approvalMode)
                    .signature(signs.get(his.getTaskId()))
                    .comment(commentVos)
                    .result(varMap.get("approve_" + his.getTaskId()))
                    .build();
        }).collect(Collectors.toList());
        //将非任务类的评论转换成流程节点
        progressNodes.addAll(commentMap.getOrDefault(instanceId, Collections.emptyList()).stream().map(cm ->
                ProcessProgressVo.ProgressNode.builder()
                        .nodeId(cm.getId())
                        .name("参与评论")
                        .user(cm.getUser())
                        .startTime(cm.getCreateTime())
                        .finishTime(cm.getCreateTime())
                        .taskId(cm.getId())
                        .comment(CollectionUtil.newArrayList(cm))
                        .result(ProcessHandlerParamsVo.Action.comment)
                        .build()).collect(Collectors.toList()));
        if (CollectionUtil.isNotEmpty(userSet)) {
            Map<String, OrgUser> map = userDeptOrLeaderService.getUserMapByIds(userSet);
            progressNodes.forEach(n -> {
                if (WflowGlobalVarDef.WFLOW_TASK_AGRRE.equals(n.getUser().getId())
                        || WflowGlobalVarDef.WFLOW_TASK_REFUSE.equals(n.getUser().getId())) {
                    n.setUser(WflowGlobalVarDef.SYS);
                } else {
                    n.setUser(map.get(n.getUser().getId()));
                    n.getComment().forEach(c -> c.setUser(map.get(c.getUser().getId())));
                }
            });
        }
        return progressNodes;
    }

    @Override
    public List<Task> getProcessInstanceTaskList(String instanceId) {
        return taskService.createTaskQuery().processInstanceId(instanceId).active().list();
    }

    @Override
    public Page<ProcessInstanceVo> getUserSubmittedList(Integer pageSize, Integer pageNo, String startUser, String code, Boolean finished) {
        HistoricProcessInstanceQuery instanceQuery = historyService.createHistoricProcessInstanceQuery();
        Executor.builder()
                .ifNotBlankNext(startUser, instanceQuery::startedBy)
                .ifNotBlankNext(code, instanceQuery::processDefinitionKey)
                .ifTrueNext(Boolean.FALSE.equals(finished), instanceQuery::unfinished);
        List<HistoricProcessInstance> historicProcessInstances = instanceQuery
                .orderByProcessInstanceStartTime().desc()
                .orderByProcessInstanceEndTime().desc()
                .listPage(pageSize * (pageNo - 1), pageSize);
        Page<ProcessInstanceVo> page = new Page<>();
        page.setTotal(instanceQuery.count());
        page.setCurrent(pageNo);
        page.setSize(pageSize);
        Map<String, String> instanceNodeMap = new HashMap<>();
        page.setRecords(getInstances(instanceNodeMap, historicProcessInstances));
        return page;
    }

    @Override
    public Page<ProcessInstanceVo> getCcMeInstance(Integer pageSize, Integer pageNo, String code) {
        LambdaQueryWrapper<WflowCcTasks> queryWrapper = new LambdaQueryWrapper<WflowCcTasks>()
                .eq(WflowCcTasks::getUserId, UserUtil.getLoginUserId());
        if (StrUtil.isNotBlank(code)) {
            queryWrapper.eq(WflowCcTasks::getCode, code);
        }
        Page<WflowCcTasks> tasks = ccTasksMapper.selectPage(new Page<>(pageNo, pageSize),
                queryWrapper.orderByDesc(WflowCcTasks::getCreateTime));
        HistoricProcessInstanceQuery instanceQuery = historyService.createHistoricProcessInstanceQuery();
        if (StrUtil.isNotBlank(code)) {
            instanceQuery.processDefinitionKey(code);
        }
        Map<String, String> instanceMap = tasks.getRecords().stream().collect(
                Collectors.toMap(WflowCcTasks::getInstanceId, WflowCcTasks::getNodeId, (v1, v2) -> v2));
        Page<ProcessInstanceVo> page = new Page<>();
        page.setCurrent(pageNo);
        page.setSize(pageSize);
        if (CollectionUtil.isNotEmpty(instanceMap)) {
            List<HistoricProcessInstance> historicProcessInstances = instanceQuery
                    .processInstanceIds(instanceMap.keySet())
                    .orderByProcessInstanceStartTime().desc()
                    .orderByProcessInstanceEndTime().desc().list();
            page.setTotal(tasks.getTotal());
            page.setRecords(getInstances(instanceMap, historicProcessInstances));
        } else {
            page.setTotal(0);
            page.setRecords(Collections.emptyList());
        }
        return page;
    }

    @Override
    public InstanceCountVo getProcessInstanceCount() {
        String userId = UserUtil.getLoginUserId();
        Long cc = ccTasksMapper.selectCount(new LambdaQueryWrapper<WflowCcTasks>().eq(WflowCcTasks::getUserId, userId));
        Long todo = taskService.createTaskQuery().taskCandidateOrAssigned(userId).count();
        Long mySubmited = historyService.createHistoricProcessInstanceQuery().startedBy(userId).unfinished().count();
        return InstanceCountVo.builder().todo(todo).mySubmited(mySubmited).cc(cc.intValue()).build();//xubz cc
    }

    /**
     * 获取抄送的流程实例信息
     *
     * @param instanceId 实例ID
     * @return 抄送我的流程
     */
    private List<ProcessProgressVo.ProgressNode> getCcTaskRecords(String instanceId) {
        Set<String> ccUsers = new HashSet<>();
        List<ProcessProgressVo.ProgressNode> ccList = ccTasksMapper.selectList(new LambdaQueryWrapper<WflowCcTasks>()
                .eq(WflowCcTasks::getInstanceId, instanceId)).stream().map(task -> {
            ccUsers.add(task.getUserId());
            return ProcessProgressVo.ProgressNode.builder()
                    .nodeId(task.getNodeId())
                    .nodeType(NodeTypeEnum.CC)
                    .name(task.getNodeName())
                    .comment(Collections.emptyList())
                    .user(OrgUser.builder().id(task.getUserId()).build())
                    .startTime(task.getCreateTime())
                    .finishTime(task.getCreateTime())
                    .build();
        }).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(ccUsers)) {
            Map<String, OrgUser> userMap = userDeptOrLeaderService.getUserMapByIds(ccUsers);
            ccList.stream().peek(v -> v.setUser(userMap.get(v.getUser().getId()))).collect(Collectors.toList());
        }
        return ccList;
    }

    /**
     * 构造流程实例列表
     *
     * @param instanceNodeMap 流程实例ID与对应节点ID映射
     * @param Instances       流程实例
     * @return 流程实例列表
     */
    private List<ProcessInstanceVo> getInstances(Map<String, String> instanceNodeMap, List<HistoricProcessInstance> Instances) {
        Set<String> staterUsers = new HashSet<>();
        List<ProcessInstanceVo> instanceVos = Instances.stream().map(ist -> {
            staterUsers.add(ist.getStartUserId());
            ProcessResultEnum processResult = ProcessResultEnum.resolveResult(ist.getEndActivityId());
            ProcessInstanceVo instanceVo = ProcessInstanceVo.builder()
                    .processDefId(ist.getProcessDefinitionId())
                    .instanceId(ist.getId())
                    .nodeId(instanceNodeMap.get(ist.getId()))
                    .formId(ist.getProcessDefinitionKey())
                    .staterUserId(ist.getStartUserId())
                    .startTime(ist.getStartTime())
                    .finishTime(ist.getEndTime())
                    .processDefName(ist.getProcessDefinitionName())
                    .status(processResult.getDesc())
                    .result(processResult)
                    .version(ist.getProcessDefinitionVersion())
                    .build();
            if (ProcessResultEnum.RUNNING.equals(instanceVo.getResult())) {
                //没有结束，还在走流程，获取任务
                List<Task> list = taskService.createTaskQuery().processInstanceId(ist.getId()).includeIdentityLinks().active().list();
                instanceVo.setNodeId(Optional.ofNullable(instanceVo.getNodeId()).orElseGet(() -> {
                    if (CollectionUtil.isNotEmpty(list)) {
                        return list.get(0).getTaskDefinitionKey();
                    }
                    return null;
                }));
                instanceVo.setTaskName(StrUtil.join("、", list.stream().map(TaskInfo::getName).collect(Collectors.toSet())));
            } else {
                instanceVo.setTaskName(instanceVo.getResult().getDesc());
            }
            return instanceVo;
        }).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(staterUsers)) {
            Map<String, OrgUser> userMap = userDeptOrLeaderService.getUserMapByIds(staterUsers);
            return instanceVos.stream().map(v -> {
                v.setStaterUser(userMap.get(v.getStaterUserId()));
                return v;
            }).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    /**
     * 获取流程处理操作权限
     *
     * @param currentNode 当前的节点
     * @return 操作权限设置
     */
    private OperationPerm getOperationPerm(ProcessNode<?> currentNode) {
        OperationPerm operationPerm = null;
        if (Objects.nonNull(currentNode)) {
            if (NodeTypeEnum.ROOT.equals(currentNode.getType())) {
                RootProps props = (RootProps) currentNode.getProps();
                operationPerm = props.getOperationPerm();
                if (Objects.isNull(operationPerm)) {
                    operationPerm = OperationPerm.builder()
                            .agree(new OperationPerm.Operations("提交", true))
                            .build();
                }
            } else if (NodeTypeEnum.APPROVAL.equals(currentNode.getType())) {
                ApprovalProps props = (ApprovalProps) currentNode.getProps();
                operationPerm = props.getOperationPerm();
                if (Objects.isNull(operationPerm)) {
                    operationPerm = OperationPerm.builder()
                            .agree(new OperationPerm.Operations("同意", true))
                            .refuse(new OperationPerm.Operations("拒绝", true))
                            .transfer(new OperationPerm.Operations("转交", true))
                            .afterAdd(new OperationPerm.Operations("加签", true))
                            .recall(new OperationPerm.Operations("退回", true))
                            .build();
                }
            } else if (NodeTypeEnum.TASK.equals(currentNode.getType())) {
                ApprovalProps props = (ApprovalProps) currentNode.getProps();
                operationPerm = props.getOperationPerm();
                if (Objects.isNull(operationPerm)) {
                    operationPerm = OperationPerm.builder()
                            .agree(new OperationPerm.Operations("提交", true))
                            .transfer(new OperationPerm.Operations("转办", true))
                            .afterAdd(new OperationPerm.Operations("加签", true))
                            .recall(new OperationPerm.Operations("退回", true))
                            .build();
                }
            }
        }
        return operationPerm;
    }

    private ProcessProgressVo.InstanceExternSetting getExternSetting(String setting, String startUser) {
        JSONObject parsed = JSONObject.parseObject(setting);
        return ProcessProgressVo.InstanceExternSetting.builder()
                .enableSign(parsed.getBoolean("sign"))
                .enableCancel(Boolean.TRUE.equals(parsed.getBoolean("enableCancel"))
                        && startUser.equals(UserUtil.getLoginUserId()))
                .build();
    }
}
